// FacebookResponse.cs
// Facebook/Framework/Service/Core
// Copyright (c) 2007, Nikhil Kothari. All Rights Reserved.
//

using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;

namespace Facebook.Service.Core {

    /// <summary>
    /// Represents a response resulting from invoking a Facebook API method.
    /// </summary>
    public sealed class FacebookResponse {

        private FacebookResponseStatus _status;
        private string _message;
        private string _method;

        private string _rawResponse;
        private object _result;

        internal FacebookResponse(HttpStatusCode errorStatusCode, string method) {
            _status = (FacebookResponseStatus)((uint)FacebookResponseStatus.HttpError | (uint)errorStatusCode);
            _method = method;
        }

        internal FacebookResponse(Stream responseStream, string method) {
            _method = method;

            StreamReader streamReader = new StreamReader(responseStream);
            _rawResponse = streamReader.ReadToEnd();
            try {
                JsonReader jsonReader = new JsonReader(new StringReader(_rawResponse));
                object result = jsonReader.ReadValue();

                Hashtable jsonObject = result as Hashtable;
                if (jsonObject != null) {
                    object errorCode = jsonObject["error_code"];
                    if (errorCode != null) {
                        _status = (FacebookResponseStatus)(int)errorCode;
                        _message = (string)jsonObject["error_msg"];
                    }
                }

                if (_status == FacebookResponseStatus.Succeeded) {
                    _result = result;
                }
            }
            catch {
                _status = FacebookResponseStatus.UnknownError;
            }
        }

        /// <summary>
        /// Gets the error message if the response represents an error.
        /// </summary>
        public string ErrorMessage {
            get {
                if (_message == null) {
                    return String.Empty;
                }
                return _message;
            }
        }

        /// <summary>
        /// Indicates whether the response represents an error.
        /// </summary>
        public bool IsError {
            get {
                return (_status != FacebookResponseStatus.Succeeded);
            }
        }

        /// <summary>
        /// Gets the raw, textual response content.
        /// </summary>
        public string RawResponse {
            get {
                return _rawResponse;
            }
        }

        /// <summary>
        /// Gets the result contained within the response.
        /// </summary>
        public object Result {
            get {
                return _result;
            }
        }

        /// <summary>
        /// Gets more specific success or failure status of the response.
        /// </summary>
        public FacebookResponseStatus Status {
            get {
                return _status;
            }
        }

        internal static bool CoerceBoolean(object o) {
            if (o is bool) {
                return (bool)o;
            }
            if (o is int) {
                return ((int)o) == 1;
            }
            if (o is string) {
                return (String.CompareOrdinal((string)o, "1") == 0);
            }
            if (o is ArrayList) {
                Debug.Assert(((ArrayList)o).Count == 1);
                Debug.Assert(((ArrayList)o)[0] is bool);
                return (bool)((ArrayList)o)[0];
            }
            return false;
        }

        internal static DateTime CoerceDateTime(object o) {
            if (o is int) {
                return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds((int)o);
            }
            if (o is long) {
                return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds((long)o);
            }
            return DateTime.MinValue;
        }

        internal static string CoerceOptions(object o) {
            Hashtable options = o as Hashtable;
            if (options == null) {
                return String.Empty;
            }

            StringBuilder sb = new StringBuilder();
            bool hasOptions = false;

            foreach (DictionaryEntry entry in options) {
                if ((entry.Value == (object)0) || (entry.Value == (object)false)) {
                    continue;
                }

                if (hasOptions) {
                    sb.Append(",");
                }
                sb.Append((string)entry.Key);
            }
            return sb.ToString();
        }

        internal static string CoerceString(object o) {
            if (o is string) {
                return (string)o;
            }
            if (o == null) {
                return String.Empty;
            }
            return o.ToString();
        }
    }
}
